/// ***************************************************************************
/// @warning Copyright (C), 1993-2011,CDSF Information Technologies Co., Ltd.
/// @file DirManager.cpp
/// @author luoshanjie
/// @version 1.0
/// @date 2011/05/18
/// @brief
/// @attention   
/// @note 
/// @<author>    <time>   <version >   <desc>
///**************************************************************************/

#include "DirManager.h"

//创建目录
int 
CDirManager::mk_dir(const char* path)
{
    int mode = S_IRWXU;    
    if(NULL == path)
    {
        return -1;
    }
    if (access(path,F_OK) == 0)
    {
        return 0;
    }
    string str_path = path;

    //最后一位如果为‘/’，那么就去掉
    if (str_path[str_path.size() - 1] == '/')
    {
        str_path.resize(str_path.size() - 1);
    }

    string::size_type pos = 0;
    while ((pos = str_path.find("/", pos)) != string::npos)
    {
        //按路径循环创建目录，如存在则继续创建下一层
        mkdir((str_path.substr(0,pos)).c_str(), mode);
        
        ++pos;
    }

    if (-1 == mkdir(path, mode))
    {
        return -1;    
    }    
        
    //创建最高层目录
    //建立目录成功后修改权限
    chmod(path, S_IRWXU | S_IRWXG);
    return 0;
}

//删除目录
int
CDirManager::rm_dir(const char* path)
{
    if(NULL == path)
    {
        return -1;
    }
    if(access(path, F_OK) == -1)
    {        
        return 0;
    }

    //最后一位如果为‘/’，那么就去掉
    string str_tmp(path);
    if(str_tmp[str_tmp.size() - 1] == '/')
    {
        str_tmp.resize(str_tmp.size() - 1);
    }
    
       
    DIR * p_dir;
    p_dir = opendir(path);
    if(NULL == p_dir)
    {
        closedir(p_dir);
        return -1;
    }
    struct dirent st_ent;
    struct dirent * resultent;
    while(readdir_r(p_dir, &st_ent, &resultent) == 0)
    {
        if(resultent == NULL)
        {
            break;
        }
        string str_path = path;
        string name = st_ent.d_name;
        if(name == "." || name == "..")
        {
            continue;
        }        
        str_path += '/';
        str_path += name;
        if(is_dir(str_path.c_str()))
        {
            if(-1 == rm_dir(str_path.c_str()))//递归删除子文件夹
            {
                closedir(p_dir);
                return -1;
            }
        }
        else
        {
            unlink(str_path.c_str());
        }
    }    

    if (-1 == rmdir(path))
    {
        closedir(p_dir);
        return -1;
    }

    closedir(p_dir);
    return 0;
}

//拷贝文件
int
CDirManager::copy_file(const char* src,const char* dest)
{
    if ((NULL == src) || (NULL == dest))
    {
        return -1;
    }
    int from_fd = -1;
    int to_fd   = -1;
    /* 打开源文件 */
    /*open file readonly,返回-1表示出错，否则返回文件描述符*/
    if ((from_fd=open(src, O_RDONLY))==-1) 
    {
        if (-1 != from_fd)
        {
            close(from_fd);
        }
        return -1;
    }

    /* 创建目的文件 */
    /* 使用了O_CREAT选项-创建文件,open()函数需要第3个参数,
    mode=S_IRUSR|S_IWUSR表示S_IRUSR 用户可以读 S_IWUSR 用户可以写*/
    if((to_fd=open(dest, O_WRONLY|O_CREAT, S_IRUSR|S_IWUSR))==-1)
    {
        if (-1 != from_fd)
        {
            close(from_fd);
        }
        if (-1 != to_fd)
        {
            close(to_fd);
        }
        return -1;
    }

    /* 以下代码是一个经典的拷贝文件的代码 */
    int bytes_read = 0;
    int bytes_write = 0;
    char buffer[BUFFER_SIZE] = {0};
    while((bytes_read = read(from_fd,buffer,BUFFER_SIZE)) > 0)
    {
        /* 一个致命的错误发生了 */
        if((bytes_read==-1)&&(errno!=EINTR))
            break;
        else if(bytes_read>0)
        {
            char* ptr=buffer;
            while((bytes_write=write(to_fd,ptr,bytes_read)) > 0)
            {
                /* 一个致命错误发生了 */
                if((bytes_write==-1)&&(errno!=EINTR))
                    break;
                /* 写完了所有读的字节 */
                else if(bytes_write==bytes_read)
                    break;
                /* 只写了一部分,继续写 */
                else if(bytes_write>0)
                {
                ptr+=bytes_write;
                bytes_read-=bytes_write;
                }
            }
            /* 写的时候发生的致命错误 */
            if(bytes_write==-1)
            break;
        }
    }
    close(from_fd);
    close(to_fd);
    return 0;
}

//移动文件
int
CDirManager::move_file(const char* src, const char* dest)
{
    if(0 != copy_file(src, dest))//复制文件
    {
        return -1;
    }
    unlink(src);//删除原文件
    return 0;
}

//获取当前文件或文件夹所在文件夹路径
int CDirManager::get_dir_path(const char* path, string & dir)
{
    //判断路径是否未空
    if(NULL == path)
    {
        return -1;
    }

    string str_path = path;

    //最后一位如果为‘/’，那么就去掉
    if(str_path[str_path.size() - 1] == '/')
    {
        str_path.resize(str_path.size() - 1);
    }

    string::size_type pos = str_path.rfind('/'); //反向查找最后一个'/'
    if(pos != string::npos)
    {
        dir = str_path.substr(0, pos);
    }
    else
    {
        dir = "."; //如果未找到'/'则说明在当前目录下
    }

    return 0;
}

//改文件夹或文件名字
int CDirManager::rename(const string& srcname,const string& destname)
{
    if(0!=::rename(srcname.c_str(), destname.c_str()))
    {
        return -1;
    }
    return 0;
}

//获取文件名
int CDirManager::get_file_name(const string &file_path, string &file_name)
{
    basic_string <char>::size_type begin_index; 
    basic_string <char>::size_type end_index;

    //反向查找最后一个'/'
    begin_index = file_path.rfind("/");

    //无效迭代器
    if(begin_index == string::npos)
    {
        //ERROR_LOG("ERROR STRING");
        return -1;
    }

    //查找文件末尾
    end_index = file_path.length();

    //无效迭代器
    if(end_index == string::npos)
    {
        //ERROR_LOG("ERROR STRING");
        return -1;
    }

    //返回最后一个'/'到文件末尾的子串
    file_name = file_path.substr(begin_index + 1, end_index);

    return 0;
}

//复制文件夹或文件
int CDirManager::cp_dir(const string src,const string& dest)
{
    if(src.empty() || dest.empty())
    {
        return -1;
    }

    if((access(src.c_str(),F_OK) != F_OK) 
        || access(dest.c_str(), F_OK) != F_OK)
    {
        return -1;
    }

    //路径规整
    string src_temp(src);
    if(src_temp[src_temp.size() - 1] == '/')
    {
        src_temp.resize(src_temp.size() - 1);
    }
    string dest_temp(dest);
    if(dest_temp[dest_temp.size() - 1] == '/')
    {
        dest_temp.resize(dest_temp.size() - 1);
    }

    string src_name;
    if (-1 == get_file_name(src_temp, src_name))
    {
        return -1;
    }
    
    dest_temp = dest_temp + "/" + src_name;
    if (-1 == mk_dir(dest_temp.c_str()))
    {
        return -1;
    }
    
    
    DIR * p_dir;
    p_dir = opendir(src_temp.c_str());
    if(NULL == p_dir)
    {
        closedir(p_dir);
        return -1;
    }
// *** BEGIN *** V100R001C01/DTS2011081704797 2011/08/27 baopeng sf0923 Add
// 修改原因: 非线程安全函数替换为线程安全函数

    struct dirent st_ent;
    struct dirent * resultent;
    while(readdir_r(p_dir, &st_ent, &resultent) == 0)
    {
        if(resultent == NULL)
        {
            break;
        }
// ***  END  *** V100R001C01/DTS2011081704797 2011/08/27 baopeng sf0923 Add 
        string name = st_ent.d_name;
        if(name == ".." || name == ".")
        {
            continue;
        }
        string src_path = src_temp + '/' + name;
        string dest_path = dest_temp + '/' + name;
        if(is_dir(src_path.c_str()))
        {
            if(-1 != mk_dir(dest_path.c_str()))
            {
                closedir(p_dir);
                return -1;
            }
            if(0 != cp_dir(src_path, dest_path))
            {
                closedir(p_dir);
                return -1;
            }
        }else
        {
            if(0 != CDirManager::copy_file(src_path.c_str(), dest_path.c_str()))
            {
                closedir(p_dir);
                return -1;
            }
        }
    }
    closedir(p_dir);
    return 0;
}

//判断是否是文件夹
int CDirManager::is_dir(const char * path)
{
    if (NULL == path)
    {
        return 0;
    }

    struct stat st;
    lstat(path, &st);
    return S_ISDIR(st.st_mode);
}

//复制文件到文件夹
int CDirManager::cp_file_to_dir(const char* in_cl_file_name, const char* in_cl_dest_path)
{
    string file_name(in_cl_file_name);
    string str_tmp(in_cl_dest_path);

    string dest_name;
    string::size_type pos = file_name.rfind('/');
    if (pos != string::npos)
    {
        dest_name = file_name.substr(pos,file_name.length() - 1);
    }
    else
    {
        dest_name += '/' + file_name;
    }

    if(str_tmp[str_tmp.size() - 1] == '/')
    {
        str_tmp.resize(str_tmp.size() - 1);
    }

    str_tmp += dest_name;

    if(-1 == copy_file(file_name.c_str(), str_tmp.c_str()))
    {    
        return -1;
    }

    return 0;
}
